package com.itheima.health.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.health.common.MessageConst;
import com.itheima.health.dao.OrderDao;
import com.itheima.health.dao.OrderSettingDao;
import com.itheima.health.entity.PageResult;
import com.itheima.health.entity.QueryPageBean;
import com.itheima.health.exception.BusinessRuntimeException;
import com.itheima.health.pojo.Order;
import com.itheima.health.pojo.OrderSetting;
import com.itheima.health.service.OrderService;
import com.itheima.health.utils.ZkClientUtil;
import com.itheima.health.vo.OrderList;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.Locker;
import org.redisson.Redisson;
import org.redisson.RedissonClient;
import org.redisson.core.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;

/**
 * 预约ServiceImpl
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderSettingDao orderSettingDao;
    @Autowired
    private OrderDao orderDao;

    private RedissonClient redissonClient = Redisson.create();

    /**
     * 分布式锁redis已添加
     * @param order
     * @return
     */
    @Transactional
    @Override

    public Order add(Order order) {
        log.info("[预约]data:{}", order);
        String lockKey = "OrderAdd";

        String clientId = UUID.randomUUID().toString();
        RLock redissonLock = redissonClient.getLock(lockKey);

        try {
            redissonLock.lock(3, TimeUnit.SECONDS);
            //查询预约设置信息
            OrderSetting orderSetting = orderSettingDao.selectByOrderDate(order.getOrderDate());
            if (null == orderSetting) {
                //如果不存在-不能预约
                throw new BusinessRuntimeException(MessageConst.SELECTED_DATE_CANNOT_ORDER);
            } else if (orderSetting.getReservations() >= orderSetting.getNumber()) {
                //如果存在-且约满
                throw new BusinessRuntimeException(MessageConst.ORDER_FULL);
            }
    public Order add(Order order){

        CuratorFramework client = ZkClientUtil.build();
        client.start();
        InterProcessMutex mutex = new InterProcessMutex(client,"/order"); // or any InterProcessLock
        try ( Locker locker = new Locker(mutex, 3000, TimeUnit.SECONDS) )
        {
            log.info("[预约]data:{}",order);
            //查询预约设置信息
            OrderSetting orderSetting = orderSettingDao.selectByOrderDate(order.getOrderDate());
            if (null == orderSetting){
                //如果不存在-不能预约
                throw new BusinessRuntimeException(MessageConst.SELECTED_DATE_CANNOT_ORDER);
            }else if(orderSetting.getReservations()>=orderSetting.getNumber()){
                //如果存在-且约满
                throw new BusinessRuntimeException(MessageConst.ORDER_FULL);
            }

            //查询是否有重复预约  同一个人同一天同一个套餐
            long count = orderDao.countByMemberAndDateAndSetMeal(order.getMemberId(),order.getOrderDate(),order.getSetmealId());
            if(count>0){
                throw new BusinessRuntimeException(MessageConst.HAS_ORDERED);
            }
            //查询是否有重复预约  同一个人同一天同一个套餐
            long count = orderDao.countByMemberAndDateAndSetMeal(order.getMemberId(), order.getOrderDate(), order.getSetmealId());
            if (count > 0) {
                throw new BusinessRuntimeException(MessageConst.HAS_ORDERED);
            }

            //插入数据
            orderDao.insert(order);

            //修改已预约数
            orderSettingDao.updateReservationsById(orderSetting.getId(),orderSetting.getReservations()+1);
            // do work
        } catch (Exception e) {
            throw new BusinessRuntimeException(MessageConst.SELECTED_DATE_CANNOT_ORDER);
        }finally {
            client.close();
        }
            //修改已预约数

            orderSettingDao.updateReservationsById(orderSetting.getId(), orderSetting.getReservations() + 1);
        } finally {
            redissonLock.unlock();
        }

        DelayQueue delayQueue = new DelayQueue();
        return orderDao.selectById(order.getId());

    }

    @Override
    public Order findById(Integer id) {

        return orderDao.selectById(id);
    }

    @Override
    public List<Map<String, Object>> countBySetmeal() {
        return orderDao.countBySetMeal();
    }

    /**
     * 删除过期预约
     * @param currentTime
     */
    @Override
    public void deleteByDate(String currentTime) {
        orderDao.deleteByCurrentTime(currentTime);
    }

    @Override
    public List<Map<String, String>> countForMemberSex() {
        return orderDao.countForMemberSex();
    }

    @Override
    public List<Map<String, String>> getMemberAgeReport() {
        return orderDao.getMemberAgeReport();
    }

    /**
     * 删除过期预约
     * @param currentTime
     */
    @Override
    public void deleteByDate(String currentTime) {
        orderDao.deleteByCurrentTime(currentTime);
    }


    /**
     * 分页查询预约列表
     * @param queryPageBean
     * @param orderDate
     * @return
     */
    @Override
    public PageResult findByPage(QueryPageBean queryPageBean, Date orderDate) {
        //使用分页插件
        PageHelper.startPage(queryPageBean.getCurrentPage(),queryPageBean.getPageSize());
//        分页查询数据库
        Page<OrderList> page = orderDao.selectByPage(queryPageBean.getQueryString(),orderDate);

        log.info("[查询预约列表成功]data:{}",page);
        return new PageResult(page.getTotal(),page.getResult());
    }
}
